﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;

namespace Sustainalytics.Utils
{
    // is a class from the old platform
    public class IpRangeFinder
    {
        readonly IPAddress _startIP;
        readonly IPAddress _endIP;
        readonly uint _sIP;
        readonly uint _eIP;

        public IpRangeFinder(IPAddress startIP, IPAddress endIP)
        {
            _startIP = startIP;
            _endIP = endIP;
            _sIP = IpToUint(startIP.GetAddressBytes());
            _eIP = IpToUint(endIP.GetAddressBytes());

            if (_sIP > _eIP)
            {
                uint swap1 = _sIP;
                _sIP = _eIP;
                _eIP = swap1;

                var swap2 = startIP;
                _startIP = endIP;
                _endIP = swap2;
            }
        }

        public bool InRange(IPAddress ipAdress)
        {
            uint ip = IpToUint(ipAdress.GetAddressBytes());
            return _sIP <= ip && ip <= _eIP;
        }

        public bool Intersects(IPAddress startIP, IPAddress endIP)
        {
            uint ip1 = IpToUint(startIP.GetAddressBytes());
            uint ip2 = IpToUint(endIP.GetAddressBytes());

            return _sIP <= ip1 && ip1 <= _eIP ||
                    _sIP <= ip2 && ip2 <= _eIP ||
                    ip1 <= _sIP && _sIP <= ip2 ||
                    ip1 <= _eIP && _eIP <= ip2;
        }

        public IEnumerable<string> GetIPRange(IPAddress startIP, IPAddress endIP)
        {
            uint sIP = IpToUint(startIP.GetAddressBytes());
            uint eIP = IpToUint(endIP.GetAddressBytes());
            while (sIP < eIP)
            {
                yield return new IPAddress(ReverseBytesArray(sIP)).ToString();
                sIP++;
            }
        }

        public IEnumerable<string> GetIPRange()
        {
            uint sIP = IpToUint(_startIP.GetAddressBytes());
            uint eIP = IpToUint(_endIP.GetAddressBytes());
            while (sIP < eIP)
            {
                yield return new IPAddress(ReverseBytesArray(sIP)).ToString();
                sIP++;
            }
        }

        /* reverse byte order in array */
        protected uint ReverseBytesArray(uint ip)
        {
            byte[] bytes = BitConverter.GetBytes(ip);
            bytes = bytes.Reverse().ToArray();
            return (uint)BitConverter.ToInt32(bytes, 0);
        }

        protected uint IpToUint(byte[] ipBytes)
        {
            ByteConverter bConvert = new ByteConverter();
            uint ipUint = 0;

            int shift = 24; // indicates number of bits left for shifting
            foreach (byte b in ipBytes)
            {
                if (ipUint == 0)
                {
                    ipUint = (uint)bConvert.ConvertTo(b, typeof(uint)) << shift;
                    shift -= 8;
                    continue;
                }

                ipUint += shift >= 8 ? (uint)bConvert.ConvertTo(b, typeof(uint)) << shift : (uint)bConvert.ConvertTo(b, typeof(uint));

                shift -= 8;
            }

            return ipUint;
        }
    }
}
